package com.gitee.wsl.mathematics.vector.vec4

import com.gitee.wsl.ext.array.DoubleArray
import com.gitee.wsl.io.dataproxy.DataGet
import com.gitee.wsl.io.dataproxy.asProxy
import com.gitee.wsl.mathematics.vector.vec2.Vec2
import com.gitee.wsl.mathematics.vector.vec3.Vec3

/**
 * A class representing a four-dimensional vector.
 */
open class Vec4(override val proxy: DataGet<Double>): Vector4D<Vec4> {
    constructor(x: Double=0.0,
                y: Double=0.0,
                z: Double=0.0,
                w: Double=0.0):this( DoubleArray(x,y,z,w).asProxy())
    constructor(a: Number) : this(a.toDouble(), a.toDouble(), a.toDouble(), a.toDouble())
    constructor(x: Number, y: Number, z: Number, w: Number) : this(x.toDouble(), y.toDouble(), z.toDouble(), w.toDouble())
    constructor(base: Vector4<*,*>) : this(base.x, base.y, base.z, base.w)

    override val self
        get() = this

    override fun createVec2(a: Double, b: Double): Vec2 = Vec2(a,b)

    override fun createVec3(a: Double, b: Double, c: Double): Vec3 = Vec3(a,b,c)

    override fun create(x: Double, y: Double, z: Double, w: Double): Vec4 = Vec4(x, y, z, w)


    override fun toString(): String {
        val xInt = x.toInt(); val yInt = y.toInt(); val zInt = z.toInt(); val wInt = w.toInt()
        val xs = if (x == xInt.toDouble()) xInt.toString() else x.toString()
        val ys = if (y == yInt.toDouble()) yInt.toString() else y.toString()
        val zs = if (z == zInt.toDouble()) zInt.toString() else z.toString()
        val ws = if (w == wInt.toDouble()) wInt.toString() else w.toString()

        return "[$xs, $ys, $zs, $ws]"
    }
    override fun equals(other: Any?) = other is Vec4 && x == other.x && y == other.y && z == other.z && w == other.w
    override fun hashCode() = 31 * (31 * (31 * x.hashCode() + y.hashCode()) + z.hashCode()) + w.hashCode()

    companion object {
        val one get() = Vec4(1.0, 1.0, 1.0, 1.0)
        val zero get() = Vec4(0.0, 0.0, 0.0, 0.0)
        val right get() = Vec4(1.0, 0.0, 0.0, 0.0)
        val left get() = Vec4(-1.0, 0.0, 0.0, 0.0)
        val up get() = Vec4(0.0, 1.0, 0.0, 0.0)
        val down get() = Vec4(0.0, -1.0, 0.0, 0.0)
        val forward get() = Vec4(0.0, 0.0, 1.0, 0.0)
        val backward get() = Vec4(0.0, 0.0, -1.0, 0.0)
        val negativeInfinity get() = Vec4(Double.NEGATIVE_INFINITY)
        val positiveInfinity get() = Vec4(Double.POSITIVE_INFINITY)
    }

}

